#ifndef _COMPLEX_CUBIC_H
#define _COMPLEX_CUBIC_H

#include "icell.h"

#include <vector>
#include <map>

// =============================================================================
//  Déclaration de la classe complexe cubique : ComplexCubic
// =============================================================================

template<int t_iDimComp, int t_iDimPoint, typename t_Type>
class ComplexCubic
{
	public:
		ComplexCubic();
		~ComplexCubic();
		
		// Est ce que le complexe cubique est valide.
		bool IsValid();
		// Ajouter une i-Cellule dans le complexe cubique.
		void AddICell(VirtualICell* p_picCell);
		// Supprime une i-Cellule du complexe cubique.
		void RemoveICell(VirtualICell* p_picCell);
		// Cherche une i-Cellule dans le complexe cubique.
		ICellPtrVect::iterator FindICell(VirtualICell* p_picCell);
		// Cherche une i-Cellule dont p_picCell serait un des bords.
		ICellPtrVect::iterator FindICellIsBorder(VirtualICell* p_picCell);
		// Effectue une réduction élémentaire.
		void BasicReduction(VirtualICell* p_pCellBord, VirtualICell* p_pCell);
		
	private:
		std::map<int, ICellPtrVect*> m_vComplexes;
		
};

// =============================================================================
//  Implantation des fonctions membres.
// =============================================================================

template<int t_iDimComp, int t_iDimPoint, typename t_Type>
ComplexCubic<t_iDimComp, t_iDimPoint, t_Type>::ComplexCubic()
{
	for (int i = 0; i <= t_iDimComp; i++)
		m_vComplexes.insert(std::pair<int, ICellPtrVect*>(i, new ICellPtrVect()));
}

// -----------------------------------------------------------------------------
template<int t_iDimComp, int t_iDimPoint, typename t_Type>
ComplexCubic<t_iDimComp, t_iDimPoint, t_Type>::~ComplexCubic()
{
	std::map<int, ICellPtrVect*>::iterator itMap; 
	ICellPtrVect::iterator itVec;
	
	for (itMap = m_vComplexes.begin(); itMap != m_vComplexes.end(); ++itMap)
	{
		ICellPtrVect vVirtICell = *(itMap->second);
		for (itVec = vVirtICell.begin(); itVec != vVirtICell.end(); )
		{
			delete (*itVec);
			itVec = vVirtICell.erase(itVec);
		}
		delete itMap->second;
	}
	m_vComplexes.clear();
}

// -----------------------------------------------------------------------------
template<int t_iDimComp, int t_iDimPoint, typename t_Type>
bool ComplexCubic<t_iDimComp, t_iDimPoint, t_Type>::IsValid()
{
	std::map<int, ICellPtrVect*>::iterator itMap;
	for (itMap = m_vComplexes.begin(); itMap != m_vComplexes.end(); ++itMap)
	{
		ICellPtrVect vVirtICell = *(itMap->second);
		ICellPtrVect::iterator itVect;
		for (itVect = vVirtICell.begin(); itVect != vVirtICell.end(); ++itVect)
		{
			const ICellPtrVect* picBorderCells = (*itVect)->GetBorderCells();
			if (picBorderCells != NULL)
			{
				for (int i = 0; i < picBorderCells->size(); i++)
				{
					if (picBorderCells->at(i) == NULL)
						return false;
				}
			}
		}
	}
	return true;
}

// -----------------------------------------------------------------------------
template<int t_iDimComp, int t_iDimPoint, typename t_Type>
void ComplexCubic<t_iDimComp, t_iDimPoint, t_Type>::AddICell(VirtualICell* p_picCell)
{
	assert(p_picCell->GetDim() <= t_iDimComp);
	m_vComplexes[p_picCell->GetDim()]->push_back(p_picCell);
}

// -----------------------------------------------------------------------------
template<int t_iDimComp, int t_iDimPoint, typename t_Type>
void ComplexCubic<t_iDimComp, t_iDimPoint, t_Type>::RemoveICell(VirtualICell* p_picCell)
{
	int iDim = p_picCell->GetDim();
	if (iDim < t_iDimComp)
	{
		assert(FindICellIsBorder(p_picCell) == m_vComplexes[iDim + 1]->end());
	}
	
	ICellPtrVect::iterator it = FindICell(p_picCell);
	delete p_picCell;
	m_vComplexes[iDim]->erase(it);
	
	std::cout << "Remove" << std::endl;
}

// -----------------------------------------------------------------------------
template<int t_iDimComp, int t_iDimPoint, typename t_Type>
ICellPtrVect::iterator ComplexCubic<t_iDimComp, t_iDimPoint, t_Type>::FindICell(VirtualICell* p_picCell)
{
	int iDim = p_picCell->GetDim();
	
	ICellPtrVect::iterator it;
	for (it = m_vComplexes[iDim]->begin(); it != m_vComplexes[iDim]->end(); ++it)
	{
		if (*it == p_picCell)
		{
			std::cout << "C'est trouvé !" << std::endl;
			return it;
		}
	}
	
	std::cout << "C'est pas trouvé." << std::endl;
	return m_vComplexes[iDim]->end();
}

// -----------------------------------------------------------------------------
template<int t_iDimComp, int t_iDimPoint, typename t_Type>
ICellPtrVect::iterator ComplexCubic<t_iDimComp, t_iDimPoint, t_Type>::FindICellIsBorder(VirtualICell* p_picCell)
{
	int iDim = p_picCell->GetDim() + 1;
	ICellPtrVect::iterator it;
	for (it = m_vComplexes[iDim]->begin(); it != m_vComplexes[iDim]->end(); ++it)
	{
		if ((*it)->IsBorder(p_picCell))
		{
			std::cout << "C'est trouvé !" << std::endl;
			return it;
		}
	}
	std::cout << "C'est pas trouvé." << std::endl;
	return m_vComplexes[iDim]->end();
}

// -----------------------------------------------------------------------------
template<int t_iDimComp, int t_iDimPoint, typename t_Type>
void ComplexCubic<t_iDimComp, t_iDimPoint, t_Type>::BasicReduction(VirtualICell* p_pCellBord, VirtualICell* p_pCell)
{
	assert(p_pCell->IsBorder(p_pCellBord));
	
	RemoveICell(p_pCell);
	RemoveICell(p_pCellBord);
}

#endif // _COMPLEX_CUBIC_H
